/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * TerrainCanvasPanel.java
 *
 * Created on 9 Ιουλ 2009, 12:12:50 μμ
 */

package gui;

import utilities.DrawingBean;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Vector;

/**
 * The canvas in which user defines the terrain details of mobility
 * @author Arvanitis Ioannis
 */
public class TerrainCanvasPanel extends javax.swing.JPanel implements MouseListener, MouseMotionListener {
    private int cell_width, cell_height;
    private int x1, x2, y1, y2;
    private static int x_cells, y_cells;
    private static Vector<DrawingBean> v = new Vector<DrawingBean>();
    private static Vector<DrawingBean> tempv = new Vector<DrawingBean>();
    private static Color color;;

    /**
     * Sets the width of canvas in cells
     * @param x_cells Width of canvas in cells
     */
    public static void setX_cells(int x_cells) {
        TerrainCanvasPanel.x_cells = x_cells;
    }

    /**
     * Gets the width of canvas in cells
     * @return the width of canvas in cells
     */
    public static int getX_cells() {
        return x_cells;
    }

    /**
     * Sets the height of canvas in cells
     * @param y_cells Height of canvas in cells
     */
    public static void setY_cells(int y_cells) {
        TerrainCanvasPanel.y_cells = y_cells;
    }

    /**
     * Gets the height of canvas in cells
     * @return the height of canvas in cells
     */
    public static int getY_cells() {
        return y_cells;
    }

    /**
     * Gets the vector with the mobility details
     * @return the vector with the mobility details
     */
    public static Vector<DrawingBean> getV() {
        return v;
    }

    /**
     * Sets the vector with the mobility details
     * @param v Vector with the mobility details
     */
    public static void setV(Vector<DrawingBean> v) {
        TerrainCanvasPanel.v = v;
    }

    /**
     * Sets the current color in canvas
     * @param color Current color in canvas
     */
    public static void setColor(Color color) {
        TerrainCanvasPanel.color = color;
    }

    /**
     * Creates new form TerrainCanvasPanel
     * @param w Width (in cells) of canvas
     * @param h Height (in cells) of canvas
     */
    public TerrainCanvasPanel(int w, int h) {
        setX_cells(w);
        setY_cells(h);
        setSize(600,400);
        setBackground(Color.WHITE);
        addMouseListener(this);
        addMouseMotionListener(this);
        v.removeAllElements();
    }

    /**
     * Mouse entered the canvas area
     * @param e MouseEvent
     */
    public void mouseEntered(MouseEvent e) {
        setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    }

   /**
     * Mouse exited the canvas area
     * @param e MouseEvent
     */
    public void mouseExited(MouseEvent e) {
		setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}

    /**
     * Mouse was pressed in the canvas area
     * @param e MouseEvent
     */
    public void mousePressed(MouseEvent e) {
		x1 = e.getX();
        y1 = e.getY();
        Point p = new Point(x1, y1);
        if (inCanvas(p)) {
            addCellInVectorByCell(findCellByPoint(p), Color.DARK_GRAY, tempv);
        }
	}

    /**
     * Mouse was released in the canvas area
     * @param e MouseEvent
     */
    public void mouseReleased(MouseEvent e) {
        for (int i=0; i<tempv.size(); i++) {
            Point p = new Point(tempv.get(i).getPoint());
            int index = findExistedCell(p, v);
            if (index == -1) {
                addCellInVectorByCell(p, color, v);
            }
            else {
                v.get(index).setColor(color);
            }
            if (color == Color.WHITE) {
                deleteCellsInVectorByColor(color, v);
            }
        }
        tempv.removeAllElements();
        repaint();
    }

    /**
     * Mouse was clicked in the canvas area
     * @param e MouseEvent
     */
    public void mouseClicked(MouseEvent e) {
        x1 = x2 = e.getX();
        y1 = y2 = e.getY();
        Point p = new Point(x1, y1);
        if (inCanvas(p)) {
            addCellInVectorByCell(findCellByPoint(p), color, v);
            if (color == Color.WHITE) {
                deleteCellsInVectorByColor(color, v);
            }
        }
    }

    /**
     * Mouse was dragged in the canvas area
     * @param e MouseEvent
     */
    public void mouseDragged(MouseEvent e) {
        x2 = e.getX();
        y2 = e.getY();
        Point p1, p2;
        if (x1 > x2) {
            if (y1 > y2) {
                p1 = new Point(x2, y2);
                p2 = new Point(x1, y1);
            }
            else {
                p1 = new Point(x2, y1);
                p2 = new Point(x1, y2);
            }
        }
        else {
            if (y1 > y2) {
                p1 = new Point(x1, y2);
                p2 = new Point(x2, y1);
            }
            else {
                p1 = new Point(x1, y1);
                p2 = new Point(x2, y2);
            }
        }
        p1 = findCellByPoint(p1);
        p2 = findCellByPoint(p2);
        tempv.removeAllElements();
        for (int i=p1.y; i<=p2.y; i++){
            for (int j=p1.x; j<=p2.x; j++){
                addCellInVectorByCell(new Point(j, i), Color.DARK_GRAY, tempv);
            }
        }
    }


    public void mouseMoved(MouseEvent e) {
    }


    @Override
    @SuppressWarnings("static-access")
    public void paintComponent(Graphics g) {
		super.paintComponent(g);

        cell_width = getWidth() / x_cells;
        cell_height = getHeight() / y_cells;

        //paint the main grid
        g.setColor(Color.LIGHT_GRAY);
        for (int i=0; i<=x_cells; i++) {
            g.drawLine(i*cell_width, 0, i*cell_width, getHeight());
        }
        for (int i=0; i<=y_cells; i++) {
            g.drawLine(0, i*cell_height, getWidth(), i*cell_height);
        }
        g.fillRect(x_cells*cell_width, 0, x_cells*cell_width, getHeight());
        g.fillRect(0, y_cells*cell_height, getWidth(), y_cells*cell_height);

        //paint the rest
        for (int i=0; i<v.size(); i++) {
            g.setColor(v.get(i).getColor());
            g.fillRect(v.get(i).getPoint().x*cell_width+1, v.get(i).getPoint().y*cell_height+1, cell_width-1, cell_height-1);
        }
        for (int i=0; i<tempv.size(); i++) {
            g.setColor(tempv.get(i).getColor());
            g.fillRect(tempv.get(i).getPoint().x*cell_width+1, tempv.get(i).getPoint().y*cell_height+1, cell_width-1, cell_height-1);
        }
    }

    /**
     * Determines whether a given pixel is contained or not in a specified area
     * @param p Given point indicating the distance from the upper left corner
     * @return whether or not this point is located in the defined canvas
     */
    private boolean inCanvas(Point p) {
        if (p.x < x_cells*cell_width && p.y < y_cells*cell_height) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * Finds the cell that contains a given pixel, or the closest cell to this one
     * @param p Point indicating a pixel in canvas
     * @return the cell that contains this given point, or the closest one
     */
    private Point findCellByPoint(Point p) {
        int x = p.x/cell_width;
        int y = p.y/cell_height;
        if (!inCanvas(p)) {
            if (p.x >= x_cells*cell_width) {
                x = x_cells-1;
            }
            if (p.y >= y_cells*cell_height) {
                y = y_cells-1;
            }
        }
        return new Point(x, y);
    }

    /**
     * Finds the index of a specified cell in a given vector
     * @param p Point we want to find
     * @param v Vector containing the data we want to locate
     * @return the index where the data were found or -1 in case of failure
     */
    private int findExistedCell(Point p, Vector<DrawingBean> v) {
        for (int i=0; i<v.size(); i++) {
            if (p.x == v.get(i).getPoint().x && p.y == v.get(i).getPoint().y) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Adds a cell in a given vector, after checking if it already exists
     * @param p Point indicating a cell (not a pixel)
     * @param c Color of the specific cell
     * @param v Vector that will add this info
     */
    private void addCellInVectorByCell(Point p, Color c, Vector<DrawingBean> v) {
        boolean alreadyExists = false;
        DrawingBean db = new DrawingBean(p, c);
        for (int i=0; i<v.size(); i++) {
            if (db.getPoint().x == v.get(i).getPoint().x && db.getPoint().y == v.get(i).getPoint().y) {
                alreadyExists = true;
                v.get(i).setColor(c);
                break;
            }
        }
        if (!alreadyExists) {
            v.addElement(db);
            repaint();
        }
    }

    /**
     * Deletes all the cells with a specified color in a given vector
     * @param c Color to delete
     * @param v Vector with data to delete
     */
    private void deleteCellsInVectorByColor(Color c, Vector<DrawingBean> v) {
        for (int i=v.size()-1; i>=0; i--) {
            if (v.get(i).getColor() == c) {
                v.removeElementAt(i);
            }
        }
        repaint();
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    








    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

}
